#ifndef SCREEN_H
#define SCREEN_H

#include <iostream>
#include <string>
#include <vector>

using namespace std;

class Screen
{
    // Window_mgr 的成员可以访问 Screen类的私有部分
    friend class Window_mgr;
public:
    typedef std::string::size_type pos;
public:
    Screen() = default;
    Screen(pos ht, pos wd, char c)
        : height(ht), width(wd), contents(ht * wd, c) {}
public:
    char get() const { return contents[cursor]; }  // 读取光标处的字符,隐式内联
    inline char get(pos r, pos c) const;  // 显式内联
    Screen &move(pos r, pos c);  // 能在之后被设为内联
    void some_member() const;
    Screen &set(char);
    Screen &set(pos, pos, char);
    // 根据对象是否是 const重载了 display函数
    Screen &dispaly(std::ostream &os) {
        do_display(os); return *this;
    }
    const Screen &dispaly(std::ostream &os) const {
        do_display(os); return *this;
    }
    pos size() const;
private:
    // 该函数负责显示Screen的内容
    void do_display(std::ostream &os) const {
        os << contents;
    }
private:
    mutable size_t access_ctr; // 即使在一个 const对象内也能被修改
    pos cursor = 0;
    pos height = 0, width = 0;
    std::string contents;
};

class Window_mgr
{
public:
    Window_mgr() = default;
public:
    // 窗口中每个屏幕的编号
    using ScreenIndex = std::vector<Screen>::size_type;
    // 按照编号将指定的 Screen重置为空白
    void clear(ScreenIndex);
    // 向窗口添加一个 Screen，返回它的编号
    ScreenIndex addScreen(const Screen&);
private:
    // 这个 Window_mgr 追踪的 Screen
    // 默认情况下，一个 Window_mgr 包含一个标准尺寸的空白 Screen
    std::vector<Screen> screens{Screen(24, 80, ' ')};
};

void Window_mgr::clear(ScreenIndex i)
{
    // s是一个Screen的引用，指向我们想要清空的那个屏幕
    Screen &s = screens[i];
    // 将那个选定的 Screen重置为空白
    s.contents = string(s.height * s.width, ' ');
}

Window_mgr::ScreenIndex Window_mgr::addScreen(const Screen &s)
{
    screens.push_back(s);
    return screens.size() - 1;
}

inline Screen &Screen::move(pos r, pos c)  // 可以在函数的定义处指定 inline
{
    pos row = r * width; // 计算行的位置
    cursor = row + c;    // 在行内将光标移动到指定的列
    return *this;        // 以左值的形式返回对象
}

void Screen::some_member() const
{
    ++access_ctr; // 保存一个计数值，用于记录成员函数被调用的次数
}

char Screen::get(pos r, pos c) const // 在类的内部声明成 inline
{
    pos row = r * width;      // 计算行的位置
    return contents[row + c]; // 返回给定列的字符
}

inline Screen &Screen::set(char c)
{
    contents[cursor] = c; // 设置当前光标所在位置的新值
    return *this;
}

inline Screen &Screen::set(pos r, pos col, char ch)
{
    contents[r * width + col] = ch; // 设置给定位置的新值
    return *this;
}

Screen::pos Screen::size() const
{
    return height * width;
}
#endif // SCREEN_H
